// @ts-check
/**
 * @typedef {{method:string,path:string}} Req {id} 将产生名为id的 path variable
 * @typedef {({query,body,pathVars})=>any} ReqHandle
 * @typedef {(ws:import('ws').WebSocket,req:import('express').Request)=>void} WsHandler
 */
/**
 * @type {Map<Req,ReqHandle>}
 */
const map = new Map();

/**
 *
 * @param {Req} finder
 * @param {ReqHandle} handler
 */
export function addRequest({ method, path }, handler) {
  // 路径是可以区分大小写的，但不能有 {} 空的 pathVariable name
  if (/\{\}/.test(path)) {
    throw new Error('无效的path，不能含有空name的pathVariable：' + path);
  }

  method = method.toUpperCase();
  path = path.replace(/\\/g, '/');

  const _exp = /\{.+?\}/g;
  const _p = path.replace(_exp, '{}');
  for (let f of map.keys()) {
    if (f.method !== method) {
      continue;
    }
    const _pExp = f.path.replace(/\{.+?\}/g, '.+?');
    if (new RegExp('^' + _pExp + '$').test(path)) {
      throw new Error('已存在相同的请求签名：' + f.method + ' ' + f.path);
    }
  }

  map.set({ method, path }, handler);
}

/**
 * @returns {[Req,ReqHandle]|undefined}
 * @param {Req} req
 */
export function findReqHandler({ method, path }) {
  method = method.toUpperCase(); // 应该可以删除

  for (let f of map.keys()) {
    if (f.method !== method) {
      continue;
    }
    const _pExp = f.path.replace(/\{.+?\}/g, '.+?');
    if (new RegExp('^' + _pExp + '$').test(path)) {
      // @ts-ignore
      return [f, map.get(f)];
    }
  }
}

/**
 *
 * @param {string} path
 * @param {string} pattern
 * @returns
 */
export function getPathVariables(path, pattern) {
  const vs = path.split('/');
  const ks = pattern.split('/');
  const obj = {};
  for (let i = 0; i < ks.length; i++) {
    if (ks[i] === vs[i]) continue;
    const key = ks[i].replace(/[\{\}]/g, '');
    obj[key] = vs[i];
  }
  return obj;
}

/** @type {Map<string,WsHandler>} */
export const wsMap = new Map();

/**
 *
 * @param {string} url
 * @param {WsHandler} handler
 */
export function addWs(url, handler) {
  if (wsMap.has(url)) {
    throw new Error('已存在相同的 webSocket url 注册');
  }
  wsMap.set(url, handler);
}
